/**
 @file ctc_asw_vlan.c

 @date 2020-07-06

 @version v1.0

---file comments----
*/
#include "ctc_asw_common.h"
#include "ctc_vlan.h"
#include "ctc_asw_vlan.h"
#include "asw/include/drv_api.h"
/***************************************************************
 *
 *  Defines and Macros
 *
 ***************************************************************/

/***************************************************************
 *
 *  Functions
 *
 ***************************************************************/
#define MAX_IVM_X_REG_NUM 16
#define VLAN_RANGE_ENTRY_NUM 4
#define IVT_PROFILE_NUM      128
#define VLAN_RANGE_GOUP_ID_CHECK(vrange_info) \
    if (vrange_info->vrange_grpid >= VLAN_RANGE_ENTRY_NUM)\
    {\
        return CTC_E_INVALID_PARAM;\
    }\
    if (!CTC_IS_BIT_SET(g_vlan_range_bitmap[lchip], vrange_info->vrange_grpid))\
    {\
        return CTC_E_NOT_EXIST;\
    }

enum ctc_vlan_hash_key_type_e
{
    CTC_VLAN_HASH_KEY_TYPE_PORT = 0,
    CTC_VLAN_HASH_KEY_TYPE_PORT_CVID,
    CTC_VLAN_HASH_KEY_TYPE_PORT_SVID,
    CTC_VLAN_HASH_KEY_TYPE_PORT_SVID_CVID,
    CTC_VLAN_HASH_KEY_TYPE_PORT_IPV4_SA,
    CTC_VLAN_HASH_KEY_TYPE_PORT_IPV6_SA ,
    CTC_VLAN_HASH_KEY_TYPE_PORT_SVID_SCOS,
    CTC_VLAN_HASH_KEY_TYPE_PORT_CVID_CCOS,
    CTC_VLAN_HASH_KEY_TYPE_MAC_SA , /*vlan class*/
    CTC_VLAN_HASH_KEY_TYPE_IPV4_SA,  /*vlan class*/
    CTC_VLAN_HASH_KEY_TYPE_IPV6_SA ,  /*vlan class*/
    CTC_VLAN_HASH_KEY_NUM,
};
typedef enum ctc_vlan_hash_key_type_e ctc_vlan_hash_key_type_t;

struct ctc_vlan_hash_key_s
{
    uint8 key_type;  /* correspond with table, see ctc_vlan_hash_key_type_t */
    uint16 gport;
    uint16 cvid;
    uint16 svid;
    mac_addr_t macsa;
    ip_addr_t ipv4_sa;
    ipv6_addr_t ipv6_sa;
};
typedef struct ctc_vlan_hash_key_s ctc_vlan_hash_key_t;

typedef int32 (* SYS_CB_VLAN_BUILD_KEY_FUNC_T)(uint8 lchip, ctc_vlan_hash_key_t* p_Key, void* p_data, uint8 is_add);

uint8 g_ivm_action_profile_idx[CTC_VLAN_TAG_OP_MAX - 1][CTC_VLAN_TAG_OP_MAX - 1] =
{
    {0x2,    0x3,   0x4,    0x5,    0x6   },       /*stag op_none, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
    {0x7,    0x8,   0x9,    0xa,    0xb   },       /*stag op_rep_or_add, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
    {0xc,    0xd,   0xe,    0xf,    0x10 },       /*stag op_add, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
    {0x11,  0x12,  0x13,  0x14,  0x15  },       /*stag op_del, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
    {0x16,  0x17,  0x18,  0x19,  0x1a  }	    /*stag op_rep, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
};

uint32 g_vlan_hash_tbl[CTC_VLAN_HASH_KEY_NUM] = { Port2vlan_t, XlateCvlanKey_t, XlateSvlanKey_t, XlateDoubleVlanKey_t, XlateIpv4Key_t,  XlateIpv6Key_t, XlateOtagKey_t, XlateItagKey_t, XlateMacKey_t, VlanHashView9_t, XlateMacKey0_t};
uint16 g_ivm_x_bitmap[CTC_MAX_LOCAL_CHIP_NUM] = {0};
uint8 g_vlan_range_bitmap[CTC_MAX_LOCAL_CHIP_NUM] = {0};

SYS_CB_VLAN_BUILD_KEY_FUNC_T g_vlan_build_key_func_cb[CTC_VLAN_HASH_KEY_NUM] = {0};

#define _____INTERNAL_API_____

STATIC int32
_ctc_asw_vlan_get_maxvid_from_vrange(uint8 lchip, ctc_vlan_range_info_t* vrange_info, ctc_vlan_range_t* vlan_range, bool is_svlan, uint16* p_max_vid)
{
    uint32 cmd = 0;
    uint16 max = 0;
    uint16 min = 0;
    uint8 idx = 0;
    int32 step = VlanRange_vlan0Max_f - VlanRange_vlan1Max_f;
    VlanRange_m vlan_range_table;

    if (0 == vlan_range->vlan_end)
    {
        return CTC_E_NONE;
    }
    CTC_MAX_VALUE_CHECK(vrange_info->vrange_grpid, VLAN_RANGE_ENTRY_NUM-1);
    if (CTC_IS_BIT_SET(g_vlan_range_bitmap[lchip], vrange_info->vrange_grpid) &&
        (CTC_IS_BIT_SET(g_vlan_range_bitmap[lchip], (vrange_info->vrange_grpid + VLAN_RANGE_ENTRY_NUM)) == is_svlan))
    {
        cmd = DRV_IOR(VlanRange_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, vrange_info->vrange_grpid, cmd, &vlan_range_table));
        for (idx = 0; idx < 4; idx++)
        {
            max = GetVlanRange(V, vlan0Max_f - step*idx, &vlan_range_table);
            min = GetVlanRange(V, vlan0Min_f - step*idx, &vlan_range_table);
            if ((vlan_range->vlan_end == max) && (vlan_range->vlan_start == min)
                && (max != min))
            {
                break;
            }
        }
    }
    else
    {
        return CTC_E_NOT_EXIST;
    }
    if (idx >= 4)
    {
        return CTC_E_NOT_EXIST;
    }
    else
    {
        *p_max_vid = max;
    }

    return CTC_E_NONE;
}

STATIC int32
_ctc_asw_vlan_mapping_get_key_type(uint8 lchip, uint32 gport, ctc_vlan_mapping_t vlan_mapping, ctc_vlan_hash_key_t* p_Key)
{
    int32 ret = 0;
    ctc_vlan_range_info_t vrange_info;
    ctc_vlan_range_t vlan_range;
    p_Key->gport = gport;
    sal_memset(&vrange_info, 0, sizeof(ctc_vlan_range_info_t));
    sal_memset(&vlan_range, 0, sizeof(vlan_range));
    switch (vlan_mapping.key
        & (CTC_VLAN_MAPPING_KEY_CVID | CTC_VLAN_MAPPING_KEY_SVID
        | CTC_VLAN_MAPPING_KEY_IPV4_SA | CTC_VLAN_MAPPING_KEY_IPV6_SA | CTC_VLAN_MAPPING_KEY_MAC_SA
        | CTC_VLAN_MAPPING_KEY_STAG_COS | CTC_VLAN_MAPPING_KEY_CTAG_COS))
    {
        case (CTC_VLAN_MAPPING_KEY_CVID):
            p_Key->key_type = CTC_VLAN_HASH_KEY_TYPE_PORT_CVID;
            p_Key->cvid = vlan_mapping.old_cvid;
            vrange_info.vrange_grpid = vlan_mapping.vrange_grpid;
            vlan_range.vlan_start = vlan_mapping.old_cvid;
            vlan_range.vlan_end = vlan_mapping.cvlan_end;
            ret = _ctc_asw_vlan_get_maxvid_from_vrange(lchip, &vrange_info, &vlan_range, FALSE, &(p_Key->cvid));
            break;
        case (CTC_VLAN_MAPPING_KEY_SVID):
            p_Key->key_type = CTC_VLAN_HASH_KEY_TYPE_PORT_SVID;
            p_Key->svid = vlan_mapping.old_svid;
            vrange_info.vrange_grpid = vlan_mapping.vrange_grpid;
            vlan_range.vlan_start = vlan_mapping.old_svid;
            vlan_range.vlan_end = vlan_mapping.svlan_end;
            ret =  _ctc_asw_vlan_get_maxvid_from_vrange(lchip, &vrange_info, &vlan_range, TRUE, &(p_Key->svid));
            break;
        case (CTC_VLAN_MAPPING_KEY_CVID | CTC_VLAN_MAPPING_KEY_SVID):
            p_Key->key_type = CTC_VLAN_HASH_KEY_TYPE_PORT_SVID_CVID;
            p_Key->cvid = vlan_mapping.old_cvid;
            p_Key->svid = vlan_mapping.old_svid;
            vrange_info.vrange_grpid = vlan_mapping.vrange_grpid;
            vlan_range.vlan_start = vlan_mapping.old_cvid;
            vlan_range.vlan_end = vlan_mapping.cvlan_end;
            ret = _ctc_asw_vlan_get_maxvid_from_vrange(lchip, &vrange_info, &vlan_range, FALSE, &(p_Key->cvid));

            vrange_info.vrange_grpid = vlan_mapping.vrange_grpid;
            vlan_range.vlan_start = vlan_mapping.old_svid;
            vlan_range.vlan_end = vlan_mapping.svlan_end;
            ret = ret ? ret : _ctc_asw_vlan_get_maxvid_from_vrange( lchip, &vrange_info, &vlan_range, TRUE, &(p_Key->svid));
            break;
        case (CTC_VLAN_MAPPING_KEY_IPV4_SA):
            p_Key->key_type = CTC_VLAN_HASH_KEY_TYPE_PORT_IPV4_SA;
            p_Key->ipv4_sa = vlan_mapping.ipv4_sa;
            break;
        case (CTC_VLAN_MAPPING_KEY_IPV6_SA):
            p_Key->key_type = CTC_VLAN_HASH_KEY_TYPE_PORT_IPV6_SA;
            sal_memcpy(&(p_Key->ipv6_sa), &(vlan_mapping.ipv6_sa), sizeof(ipv6_addr_t) );
            break;
        case (CTC_VLAN_MAPPING_KEY_CVID | CTC_VLAN_MAPPING_KEY_CTAG_COS):
            p_Key->key_type = CTC_VLAN_HASH_KEY_TYPE_PORT_CVID_CCOS;
            vrange_info.vrange_grpid = vlan_mapping.vrange_grpid;
            vlan_range.vlan_start = vlan_mapping.old_cvid;
            vlan_range.vlan_end = vlan_mapping.cvlan_end;
            ret = _ctc_asw_vlan_get_maxvid_from_vrange(lchip, &vrange_info, &vlan_range, FALSE, &(p_Key->cvid));
            p_Key->cvid = vlan_mapping.old_cvid | (vlan_mapping.old_ccos<<13) | ((vlan_mapping.old_ccos>>3)&0x1)<<12;
            break;
        case (CTC_VLAN_MAPPING_KEY_SVID | CTC_VLAN_MAPPING_KEY_STAG_COS):
            p_Key->key_type = CTC_VLAN_HASH_KEY_TYPE_PORT_SVID_SCOS;
            vrange_info.vrange_grpid = vlan_mapping.vrange_grpid;
            vlan_range.vlan_start = vlan_mapping.old_svid;
            vlan_range.vlan_end = vlan_mapping.svlan_end;
            ret =  _ctc_asw_vlan_get_maxvid_from_vrange(lchip, &vrange_info, &vlan_range, TRUE, &(p_Key->svid));
            p_Key->svid = vlan_mapping.old_svid | (vlan_mapping.old_scos<<13) | ((vlan_mapping.old_scos>>3)&0x1)<<12;
            break;
	case (CTC_VLAN_MAPPING_KEY_NONE):
            p_Key->key_type = CTC_VLAN_HASH_KEY_TYPE_PORT;
            break;
	default:
            return CTC_E_NOT_SUPPORT;
    }

    return ret;
}

STATIC int32
_ctc_asw_vlan_build_cvlan_key(uint8 lchip, ctc_vlan_hash_key_t* p_Key, void* p_data, uint8 is_add)
{
    CTC_MAX_VALUE_CHECK(p_Key->cvid, CTC_ASW_MAX_VLAN);
    SetXlateCvlanKey(V, cvid_f, p_data, p_Key->cvid);
    SetXlateCvlanKey(V, sport_f, p_data, p_Key->gport);
    SetXlateCvlanKey(V, keyType_f, p_data, 0x6);
    SetXlateCvlanKey(V, valid_f, p_data, (is_add ? 1:0));

    return CTC_E_NONE;
}

STATIC int32
_ctc_asw_vlan_build_svlan_key(uint8 lchip, ctc_vlan_hash_key_t* p_Key, void* p_data, uint8 is_add)
{
    CTC_MAX_VALUE_CHECK(p_Key->svid, CTC_ASW_MAX_VLAN);
    SetXlateSvlanKey(V, svid_f, p_data, p_Key->svid);
    SetXlateSvlanKey(V, sport_f, p_data, p_Key->gport);
    SetXlateSvlanKey(V, keyType_f, p_data, 0x4 );
    SetXlateSvlanKey(V, valid_f, p_data, (is_add ? 1:0));

    return CTC_E_NONE;
}

STATIC int32
_ctc_asw_vlan_build_double_vlan_key(uint8 lchip, ctc_vlan_hash_key_t* p_Key, void* p_data, uint8 is_add)
{
    CTC_MAX_VALUE_CHECK(p_Key->svid, CTC_ASW_MAX_VLAN);
    CTC_MAX_VALUE_CHECK(p_Key->cvid, CTC_ASW_MAX_VLAN);
    SetXlateDoubleVlanKey(V, cvid_f, p_data, p_Key->cvid);
    SetXlateDoubleVlanKey(V, svid_f, p_data, p_Key->svid);
    SetXlateDoubleVlanKey(V, sport_f, p_data, p_Key->gport);
    SetXlateDoubleVlanKey(V, keyType_f, p_data, 0x5 );
    SetXlateDoubleVlanKey(V, valid_f, p_data, (is_add ? 1:0));

    return CTC_E_NONE;
}

STATIC int32
_ctc_asw_vlan_build_port_ipv4_key(uint8 lchip, ctc_vlan_hash_key_t* p_Key, void* p_data, uint8 is_add)
{
    SetXlateIpv4Key(V, sip_f, p_data, p_Key->ipv4_sa);
    SetXlateIpv4Key(V, sport_f, p_data, p_Key->gport);
    SetXlateIpv4Key(V, keyType_f, p_data, 0x2 );
    SetXlateIpv4Key(V, valid_f, p_data, (is_add ? 1:0));

    return CTC_E_NONE;
}

STATIC int32
_ctc_asw_vlan_build_port_ipv6_key(uint8 lchip, ctc_vlan_hash_key_t* p_Key, void* p_data, uint8 is_add)
{
    ipv6_addr_t hw_ip6 = {0};
    CTC_ASW_REVERT_IP6(hw_ip6, (uint32*)p_Key->ipv6_sa);
    SetXlateMacKey0(A, sip_f, p_data, hw_ip6);
    SetXlateMacKey0(V, sport_f, p_data, p_Key->gport);
    SetXlateMacKey0(V, keyType_f, p_data, 0xA );
    SetXlateMacKey0(V, valid_f, p_data, (is_add ? 1:0));

    return CTC_E_NONE;
}

STATIC int32
_ctc_asw_vlan_build_cvlan_ccos_key(uint8 lchip, ctc_vlan_hash_key_t* p_Key, void* p_data, uint8 is_add)
{
    CTC_MAX_VALUE_CHECK(p_Key->cvid&0xFFF, CTC_ASW_MAX_VLAN);
    CTC_MAX_VALUE_CHECK((p_Key->cvid>>13)&0x7, 7);
    SetXlateItagKey(V, itag_f, p_data, p_Key->cvid);
    SetXlateItagKey(V, sport_f, p_data, p_Key->gport);
    SetXlateItagKey(V, keyType_f, p_data, 0x8);
    SetXlateItagKey(V, valid_f, p_data, (is_add ? 1:0));

    return CTC_E_NONE;
}

STATIC int32
_ctc_asw_vlan_build_svlan_scos_key(uint8 lchip, ctc_vlan_hash_key_t* p_Key, void* p_data, uint8 is_add)
{
    CTC_MAX_VALUE_CHECK(p_Key->svid&0xFFF, CTC_ASW_MAX_VLAN);
    CTC_MAX_VALUE_CHECK((p_Key->svid>>13)&0x7, 7);
    SetXlateOtagKey(V, otag_f, p_data, p_Key->svid);
    SetXlateOtagKey(V, sport_f, p_data, p_Key->gport);
    SetXlateOtagKey(V, keyType_f, p_data, 0x7 );
    SetXlateOtagKey(V, valid_f, p_data, (is_add ? 1:0));

    return CTC_E_NONE;
}

STATIC int32
_ctc_asw_vlan_build_mac_key(uint8 lchip, ctc_vlan_hash_key_t* p_Key, void* p_data, uint8 is_add)
{
    hw_mac_addr_t hw_mac =  {0};
    CTC_ASW_SET_HW_MAC(hw_mac, (uint8*)(p_Key->macsa));
    SetXlateMacKey(A, sa_f, p_data, hw_mac);
    SetXlateMacKey(V, keyType_f, p_data, 0x1 );
    SetXlateMacKey(V, valid_f, p_data, (is_add ? 1:0));

    return CTC_E_NONE;
}

STATIC int32
_ctc_asw_vlan_build_ipv4_key(uint8 lchip, ctc_vlan_hash_key_t* p_Key, void* p_data, uint8 is_add)
{
    SetVlanHashView9(V, sip_f, p_data, p_Key->ipv4_sa);
    SetVlanHashView9(V, keyType_f, p_data, 0x9 );
    SetVlanHashView9(V, valid_f, p_data, (is_add ? 1:0));

    return CTC_E_NONE;
}

STATIC int32
_ctc_asw_vlan_build_ipv6_key(uint8 lchip, ctc_vlan_hash_key_t* p_Key, void* p_data, uint8 is_add)
{
    ipv6_addr_t hw_ip6 = {0};
    CTC_ASW_REVERT_IP6(hw_ip6, (uint32*)p_Key->ipv6_sa);
    SetXlateIpv6Key(A, sip_f, p_data, hw_ip6);
    SetXlateIpv6Key(V, keyType_f, p_data, 0x3 );
    SetXlateIpv6Key(V, valid_f, p_data, (is_add ? 1:0));

    return CTC_E_NONE;
}

STATIC int32
_ctc_asw_vlan_mapping_build_cam_key(uint8 lchip, uint32 gport, ctc_vlan_mapping_t* p_vlan_mapping, void* p_data, void* p_mask)
{
    hw_mac_addr_t hw_mac;
       if( CTC_FLAG_ISSET(p_vlan_mapping->key, CTC_VLAN_MAPPING_KEY_CTAG_COS) || 
           CTC_FLAG_ISSET(p_vlan_mapping->key, CTC_VLAN_MAPPING_KEY_STAG_COS) ||
           CTC_FLAG_ISSET(p_vlan_mapping->key, CTC_VLAN_MAPPING_KEY_IPV4_SA)  ||
           CTC_FLAG_ISSET(p_vlan_mapping->key, CTC_VLAN_MAPPING_KEY_IPV6_SA) )
       {
           return CTC_E_INTR_INVALID_PARAM;
       }

    if(CTC_FLAG_ISSET(p_vlan_mapping->key, CTC_VLAN_MAPPING_KEY_CVID))
    {
        if (p_vlan_mapping->old_svid != CTC_MAX_UINT16_VALUE)
        {
            CTC_MAX_VALUE_CHECK(p_vlan_mapping->old_cvid, CTC_ASW_MAX_VLAN);
            SetIvmXReg(V, cvid_f, p_data, p_vlan_mapping->old_cvid);
            if (p_vlan_mapping->cvlan_end)
            {
                SetIvmXMaskReg(V, cvidMask_f, p_mask,  p_vlan_mapping->cvlan_end);
            }
            else
            {
                SetIvmXMaskReg(V, cvidMask_f, p_mask,  0xFFF);
            }
            SetIvmXReg(V, ctagStatus_f, p_data, 3);
            SetIvmXMaskReg(V, ctagStatusMask_f, p_mask,  0x1);
        }
        else
        {
            SetIvmXReg(V, ctagStatus_f, p_data, 0);
            SetIvmXMaskReg(V, ctagStatusMask_f, p_mask,  0x1);
        }
    }

    if(CTC_FLAG_ISSET(p_vlan_mapping->key, CTC_VLAN_MAPPING_KEY_SVID))
    {
        if (p_vlan_mapping->old_svid != CTC_MAX_UINT16_VALUE)
        {
            CTC_MAX_VALUE_CHECK(p_vlan_mapping->old_svid, CTC_ASW_MAX_VLAN);
            SetIvmXReg(V, svid_f, p_data, p_vlan_mapping->old_svid);
            if (p_vlan_mapping->svlan_end)
            {
                SetIvmXMaskReg(V, svidMask_f, p_mask, p_vlan_mapping->svlan_end);
            }
            else
            {
                SetIvmXMaskReg(V, svidMask_f, p_mask, 0xFFF);
            }
            SetIvmXReg(V, stagStatus_f, p_data, 3);
            SetIvmXMaskReg(V, stagStatusMask_f, p_mask,  0x1);
        }
        else
        {
            SetIvmXReg(V, stagStatus_f, p_data, 0);
            SetIvmXMaskReg(V, stagStatusMask_f, p_mask,  0x1);
        }
    }

    if(CTC_FLAG_ISSET(p_vlan_mapping->key, CTC_VLAN_MAPPING_KEY_MAC_SA) )
    {
        CTC_ASW_SET_HW_MAC(hw_mac, (uint8*)(p_vlan_mapping->macsa));
        SetIvmXReg(A, sa_f, p_data, hw_mac);
        if (p_vlan_mapping->old_ccos)
        {
            /*mac sa mask have 6 byte, each bit masks each byte*/
            SetIvmXMaskReg(V, saMask_f, p_mask,  p_vlan_mapping->old_ccos);
        }
        else
        {
            SetIvmXMaskReg(V, saMask_f, p_mask,  0x3F);
        }
    }
    if (gport != CTC_MAX_UINT16_VALUE)
    {
        SetIvmXReg(V, sport_f, p_data, gport);
        SetIvmXMaskReg(V, sportMask_f, p_mask,  0x1);
    }
    SetIvmXReg(V, valid_f, p_data,  0x01);

    return CTC_E_NONE;
}

STATIC int32
_ctc_asw_vlan_mapping_build_ad(uint8 lchip, ctc_vlan_mapping_t* p_vlan_mapping, void* p_data)
{
    ctc_vlan_tag_sl_t scos_action;
    ctc_vlan_tag_sl_t ccos_action;
    CTC_MAX_VALUE_CHECK(p_vlan_mapping->new_scos, 7);
    CTC_MAX_VALUE_CHECK(p_vlan_mapping->new_ccos, 7);
    CTC_MAX_VALUE_CHECK(p_vlan_mapping->new_svid, CTC_ASW_MAX_VLAN);
    CTC_MAX_VALUE_CHECK(p_vlan_mapping->new_cvid, CTC_ASW_MAX_VLAN);
    switch (p_vlan_mapping->scos_sl)
    {
        case CTC_VLAN_TAG_SL_AS_PARSE :
            scos_action = 0x3;
            break;
        case CTC_VLAN_TAG_SL_ALTERNATIVE :
            scos_action = 0x2;
            break;
        case CTC_VLAN_TAG_SL_NEW:
            scos_action = 0x1;
            break;
        case CTC_VLAN_TAG_SL_DEFAULT :
            scos_action = 0x1;
            break;
        default:
            return CTC_E_NOT_SUPPORT;
    }

    switch (p_vlan_mapping->ccos_sl)
    {
        case CTC_VLAN_TAG_SL_AS_PARSE :
            ccos_action = 0x3;
            break;
        case CTC_VLAN_TAG_SL_ALTERNATIVE :
            ccos_action = 0x2;
            break;
        case CTC_VLAN_TAG_SL_NEW:
            ccos_action = 0x1;
            break;
        case CTC_VLAN_TAG_SL_DEFAULT :
            ccos_action = 0x1;
            break;
        default:
            return CTC_E_NOT_SUPPORT;
    }

    if ((p_vlan_mapping->stag_op > CTC_VLAN_TAG_OP_VALID) | (p_vlan_mapping->ctag_op > CTC_VLAN_TAG_OP_VALID) )
    {
        return CTC_E_INVALID_PARAM;
    }
    if (p_vlan_mapping->stag_op == CTC_VLAN_TAG_OP_VALID)
    {
        p_vlan_mapping->stag_op = CTC_VLAN_TAG_OP_NONE;
    }

    if (p_vlan_mapping->ctag_op == CTC_VLAN_TAG_OP_VALID)
    {
        p_vlan_mapping->ctag_op = CTC_VLAN_TAG_OP_NONE;
    }

    CTC_MAX_VALUE_CHECK(p_vlan_mapping->policer_id, 0x3F);
    if (p_vlan_mapping->policer_id && CTC_FLAG_ISSET(p_vlan_mapping->action, CTC_VLAN_MAPPING_FLAG_STATS_EN))
    {
        return CTC_E_INVALID_PARAM;
    }
    if (p_vlan_mapping->policer_id)
    {
        SetIvmTable(V, policeIndex_f, p_data, p_vlan_mapping->policer_id);
        SetIvmTable(V, policeMode_f, p_data, 1);
        SetIvmTable(V, counterIndex_f, p_data, p_vlan_mapping->policer_id+CTC_ASW_MAX_STATS_ID+1);
        SetIvmTable(V, counterEnable_f, p_data, 1);
    }
    if(CTC_FLAG_ISSET(p_vlan_mapping->action, CTC_VLAN_MAPPING_FLAG_STATS_EN))
    {
        CTC_MAX_VALUE_CHECK(p_vlan_mapping->stats_id, CTC_ASW_MAX_STATS_ID);
        SetIvmTable(V, counterIndex_f, p_data, p_vlan_mapping->stats_id);
        SetIvmTable(V, counterEnable_f, p_data, 1);
    }
    if (p_vlan_mapping->stag_op || p_vlan_mapping->ctag_op)
    {
        SetIvmTable(V, isvidMode_f, p_data, (CTC_VLAN_TAG_OP_DEL == p_vlan_mapping->stag_op)?1:0);
        SetIvmTable(V, svid_f, p_data, p_vlan_mapping->new_svid);
        SetIvmTable(V, cvid_f, p_data, p_vlan_mapping->new_cvid);
        SetIvmTable(V, remarkScos_f, p_data, (p_vlan_mapping->new_scos << 1));
        SetIvmTable(V, remarkCcos_f, p_data, (p_vlan_mapping->new_ccos << 1));
        SetIvmTable(V, remarkScosMode_f, p_data, scos_action);
        SetIvmTable(V, remarkCcosMode_f, p_data, ccos_action);
        SetIvmTable(V, tagActionProfilePtr_f, p_data, g_ivm_action_profile_idx[p_vlan_mapping->stag_op][p_vlan_mapping->ctag_op]);
    }
    SetIvmTable(V, valid_f, p_data, 1);
    return CTC_E_NONE;
}

STATIC int32
_ctc_asw_vlan_get_ad_index(uint8 lchip, uint8 key_type, void* p_data, uint16* ad_index)
{
    switch (key_type)
    {
        case CTC_VLAN_HASH_KEY_TYPE_PORT_CVID :
            *ad_index = GetXlateCvlanKey(V, ivmIndex_f, p_data);
            break;
        case CTC_VLAN_HASH_KEY_TYPE_PORT_SVID :
            *ad_index = GetXlateSvlanKey(V, ivmIndex_f, p_data);
            break;
        case CTC_VLAN_HASH_KEY_TYPE_PORT_SVID_CVID :
            *ad_index = GetXlateDoubleVlanKey(V, ivmIndex_f, p_data);
            break;
        case CTC_VLAN_HASH_KEY_TYPE_PORT_IPV4_SA :
            *ad_index = GetXlateIpv4Key(V, ivmIndex_f, p_data);
            break;
        case CTC_VLAN_HASH_KEY_TYPE_PORT_IPV6_SA :
            *ad_index = GetXlateIpv6Key(V, ivmIndex_f, p_data);
            break;
		case CTC_VLAN_HASH_KEY_TYPE_PORT_SVID_SCOS :
            *ad_index = GetXlateOtagKey(V, ivmIndex_f, p_data);
            break;
        case CTC_VLAN_HASH_KEY_TYPE_PORT_CVID_CCOS :
            *ad_index = GetXlateItagKey(V, ivmIndex_f, p_data);
            break;
        case CTC_VLAN_HASH_KEY_TYPE_MAC_SA :
            *ad_index = GetXlateMacKey(V, ivmIndex_f, p_data);
            break;
        case CTC_VLAN_HASH_KEY_TYPE_IPV4_SA :
            *ad_index = GetVlanHashView9(V, ivmIndex_f, p_data);
            break;
        case CTC_VLAN_HASH_KEY_TYPE_IPV6_SA :
            *ad_index = GetXlateMacKey0(V, ivmIndex_f, p_data);
            break;
        default:
            return CTC_E_INVALID_PARAM;
    }
	return CTC_E_NONE;
}

STATIC int32
_ctc_asw_vlan_class_build_cam_key(uint8 lchip, ctc_vlan_class_t* p_vlan_class, void* p_data, void* p_mask)
{
    hw_mac_addr_t hw_mac;
    switch (p_vlan_class->type) /*cam*/
    {
        case CTC_VLAN_CLASS_MAC:
	      CTC_ASW_SET_HW_MAC(hw_mac, (uint8*)(p_vlan_class->vlan_class.mac));
            SetIvmXReg(A, sa_f, p_data, hw_mac);
            SetIvmXMaskReg(V, saMask_f, p_mask,  0x3F);
            SetIvmXReg(V, valid_f, p_data,  0x01);
            break;
        case CTC_VLAN_CLASS_PROTOCOL:
            SetIvmXReg(V, etherType_f, p_data, p_vlan_class->vlan_class.ether_type);
            SetIvmXMaskReg(V, etherTypeMask_f, p_mask,  0x1);
            SetIvmXReg(V, valid_f, p_data,  0x01);
            break;
        default :
            return CTC_E_NOT_SUPPORT;
    }
    return CTC_E_NONE;
}

STATIC int32
_ctc_asw_vlan_create_destroy_vlan(uint8 lchip, uint16 vlan_id, uint16 fid, uint8 en)
{
    int32  ret = 0;
    uint32 cmd = 0;
    IvtTable_m ivt;
    EvtTable_m evt;
    uint32 ivt_pro_index = 0;
    cmd = DRV_IOR(IvtTable_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, vlan_id, cmd, &ivt);
    cmd = DRV_IOR(EvtTable_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : (DRV_IOCTL(lchip, vlan_id, cmd, &evt));
    if (GetIvtTable(V, valid_f, &ivt))
    {
        ret = en ? CTC_E_EXIST : ret;
    }
    else
    {
        ret = en ? ret : CTC_E_NOT_EXIST;
    }
    ivt_pro_index = (fid < 128) ? fid : 0;
    SetIvtTable(V, fid_f, &ivt, fid);
    SetIvtTable(V, vlanProfileIndex_f, &ivt, ivt_pro_index);
    SetIvtTable(V, vlanMember_f, &ivt, 0);
    SetEvtTable(V, vlanMember_f, &evt, 0);
    SetIvtTable(V, valid_f, &ivt, en);
    SetEvtTable(V, valid_f, &evt, en);
    cmd = DRV_IOW(IvtTable_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : (DRV_IOCTL(lchip, vlan_id, cmd, &ivt));
    cmd = DRV_IOW(EvtTable_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : (DRV_IOCTL(lchip, vlan_id, cmd, &evt));
    return ret;
}
STATIC int32
_ctc_asw_vlan_register_build_key_fn()
{
    g_vlan_build_key_func_cb[CTC_VLAN_HASH_KEY_TYPE_PORT_CVID]    =  _ctc_asw_vlan_build_cvlan_key;
    g_vlan_build_key_func_cb[CTC_VLAN_HASH_KEY_TYPE_PORT_SVID]    =  _ctc_asw_vlan_build_svlan_key;
    g_vlan_build_key_func_cb[CTC_VLAN_HASH_KEY_TYPE_PORT_SVID_CVID]  =  _ctc_asw_vlan_build_double_vlan_key;
    g_vlan_build_key_func_cb[CTC_VLAN_HASH_KEY_TYPE_PORT_IPV4_SA]   =  _ctc_asw_vlan_build_port_ipv4_key;
    g_vlan_build_key_func_cb[CTC_VLAN_HASH_KEY_TYPE_PORT_IPV6_SA]   = _ctc_asw_vlan_build_port_ipv6_key;
    g_vlan_build_key_func_cb[CTC_VLAN_HASH_KEY_TYPE_PORT_CVID_CCOS]    =  _ctc_asw_vlan_build_cvlan_ccos_key;
    g_vlan_build_key_func_cb[CTC_VLAN_HASH_KEY_TYPE_PORT_SVID_SCOS]    =  _ctc_asw_vlan_build_svlan_scos_key;
    g_vlan_build_key_func_cb[CTC_VLAN_HASH_KEY_TYPE_MAC_SA]   =  _ctc_asw_vlan_build_mac_key;
    g_vlan_build_key_func_cb[CTC_VLAN_HASH_KEY_TYPE_IPV4_SA]   =  _ctc_asw_vlan_build_ipv4_key;
    g_vlan_build_key_func_cb[CTC_VLAN_HASH_KEY_TYPE_IPV6_SA]   =  _ctc_asw_vlan_build_ipv6_key;
    return CTC_E_NONE;
}

#define __BASIC_VLAN_API__
/**
 @brief The function is to create a vlan with uservlanptr
*/
int32
ctc_asw_vlan_create_uservlan(uint8 lchip, ctc_vlan_uservlan_t* user_vlan)
{
    int32 ret = CTC_E_NONE;
    uint16 fid = 0;

    CTC_ASW_FID_RANGE_CHECK(user_vlan->fid);
    CTC_VLAN_RANGE_CHECK(user_vlan->vlan_id);

    /*get fid value, default equal vlan id*/
    fid = user_vlan->fid? user_vlan->fid:user_vlan->vlan_id;

    CTC_API_LOCK(lchip);
    ret = _ctc_asw_vlan_create_destroy_vlan(lchip, user_vlan->vlan_id, fid, 1);
    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
ctc_asw_vlan_destroy_vlan(uint8 lchip, uint16 vlan_id)
{
    int32 ret = CTC_E_NONE;
    CTC_VLAN_RANGE_CHECK(vlan_id);

    CTC_API_LOCK(lchip);
    ret = _ctc_asw_vlan_create_destroy_vlan(lchip, vlan_id, 0, 0);
    CTC_API_UNLOCK(lchip);

    return ret;
}

/**
 @brief The function is to add member ports to a vlan
*/
int32
ctc_asw_vlan_add_ports(uint8 lchip, uint16 vlan_id, ctc_port_bitmap_t port_bitmap)
{
    int32  ret = 0;
    uint32 cmd = 0;
    uint32 igs_bitmap = 0;
    uint32 egs_bitmap = 0;
    IvtTable_m ivt;
    EvtTable_m evt;

    CTC_VLAN_RANGE_CHECK(vlan_id);

    sal_memset(&ivt, 0, sizeof(ivt));
    sal_memset(&evt, 0, sizeof(evt));

    CTC_API_LOCK(lchip);
    cmd = DRV_IOR(IvtTable_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, vlan_id, cmd, &ivt);
    if (!GetIvtTable(V, valid_f, &ivt))
    {
        ret = ret ? ret : CTC_E_NOT_EXIST;
    }
    cmd = DRV_IOR(EvtTable_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : (DRV_IOCTL(lchip, vlan_id, cmd, &evt));
    igs_bitmap = GetIvtTable(V, vlanMember_f, &ivt);
    egs_bitmap = GetEvtTable(V, vlanMember_f, &evt);
    igs_bitmap |= port_bitmap[0];
    egs_bitmap |= port_bitmap[0];
    SetIvtTable(V, vlanMember_f, &ivt, igs_bitmap);
    SetEvtTable(V, vlanMember_f, &evt, egs_bitmap);
    cmd = DRV_IOW(IvtTable_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : (DRV_IOCTL(lchip, vlan_id, cmd, &ivt));
    cmd = DRV_IOW(EvtTable_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : (DRV_IOCTL(lchip, vlan_id, cmd, &evt));
    CTC_API_UNLOCK(lchip);

    return ret;
}

/**
 @brief The function is to remove member ports to a vlan
*/
int32
ctc_asw_vlan_remove_ports(uint8 lchip, uint16 vlan_id, ctc_port_bitmap_t port_bitmap)
{
    int32  ret = 0;
    uint32 cmd = 0;
    uint32 igs_bitmap = 0;
    uint32 egs_bitmap = 0;
    uint8 lport;
    IvtTable_m ivt;
    EvtTable_m evt;

    CTC_VLAN_RANGE_CHECK(vlan_id);

    CTC_API_LOCK(lchip);
    cmd = DRV_IOR(IvtTable_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, vlan_id, cmd, &ivt);
    if (!GetIvtTable(V, valid_f, &ivt))
    {
        ret = ret ? ret : CTC_E_NOT_EXIST;
    }
    cmd = DRV_IOR(EvtTable_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : (DRV_IOCTL(lchip, vlan_id, cmd, &evt));
    igs_bitmap = GetIvtTable(V, vlanMember_f, &ivt);
    egs_bitmap = GetEvtTable(V, vlanMember_f, &evt);
    for (lport = 0; lport < CTC_ASW_MAX_PORT_NUM_PER_CHIP; lport ++)
    {
        if ((CTC_IS_BIT_SET(port_bitmap[0], lport)) && (CTC_IS_BIT_SET(igs_bitmap, lport)))
        {
            CTC_BIT_UNSET(igs_bitmap, lport);
            CTC_BIT_UNSET(egs_bitmap, lport);
        }
        else if (CTC_IS_BIT_SET(port_bitmap[0], lport))
        {
            ret = CTC_E_NOT_EXIST;
        }
    }
    SetIvtTable(V, vlanMember_f, &ivt, igs_bitmap);
    SetEvtTable(V, vlanMember_f, &evt, egs_bitmap);
    cmd = DRV_IOW(IvtTable_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : (DRV_IOCTL(lchip, vlan_id, cmd, &ivt));
    cmd = DRV_IOW(EvtTable_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : (DRV_IOCTL(lchip, vlan_id, cmd, &evt));
    CTC_API_UNLOCK(lchip);

    return ret;
}
/**
 @brief The function is to show vlan's member port
*/
int32
ctc_asw_vlan_get_ports(uint8 lchip, uint16 vlan_id, uint8 gchip, ctc_port_bitmap_t port_bitmap)
{
    int32  ret = 0;
    uint32 cmd = 0;
    IvtTable_m ivt;

    CTC_VLAN_RANGE_CHECK(vlan_id);

    CTC_API_LOCK(lchip);
    cmd = DRV_IOR(IvtTable_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, vlan_id, cmd, &ivt);
    if (GetIvtTable(V, valid_f, &ivt))
    {
        port_bitmap[0] = GetIvtTable(V, vlanMember_f, &ivt);
    }
    else
    {
        ret = ret ? ret : CTC_E_NOT_EXIST;
    }
    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
ctc_asw_vlan_set_property(uint8 lchip, uint16 vlan_id, ctc_vlan_property_t vlan_prop, uint32 value)
{
    int32  ret = 0;
    uint32 cmd = 0;
    IvtTable_m ivt_table;

    CTC_VLAN_RANGE_CHECK(vlan_id);
    if (CTC_VLAN_PROP_FID == vlan_prop)
    {
        CTC_ASW_FID_RANGE_CHECK(value);
    }

    CTC_API_LOCK(lchip);
    cmd = DRV_IOR(IvtTable_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, vlan_id, cmd, &ivt_table);
    if (!GetIvtTable(V, valid_f, &ivt_table))
    {
        ret = ret ? ret : CTC_E_NOT_EXIST;
    }
    switch (vlan_prop)
    {
        case CTC_VLAN_PROP_FID:
            SetIvtTable(V, fid_f, &ivt_table, value);
            cmd = DRV_IOW(IvtTable_t, DRV_ENTRY_FLAG);
            ret = ret ? ret : (DRV_IOCTL(lchip, vlan_id, cmd, &ivt_table));
            break;
        default:
            ret = CTC_E_INVALID_PARAM;
		break;
    }
    CTC_API_UNLOCK(lchip);

    return ret;

}

int32
ctc_asw_vlan_get_property(uint8 lchip, uint16 vlan_id, ctc_vlan_property_t vlan_prop, uint32* value)
{
    int32  ret = 0;
    uint32 cmd = 0;
    IvtTable_m ivt_table;

    CTC_PTR_VALID_CHECK(value);
    CTC_VLAN_RANGE_CHECK(vlan_id);

    CTC_API_LOCK(lchip);
    cmd = DRV_IOR(IvtTable_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, vlan_id, cmd, &ivt_table);
    if (!GetIvtTable(V, valid_f, &ivt_table))
    {
        ret = ret ? ret : CTC_E_NOT_EXIST;
    }
    switch (vlan_prop)
    {
        case CTC_VLAN_PROP_FID:
            *value = GetIvtTable(V, fid_f, &ivt_table);
            break;
        default:
            ret =  CTC_E_INVALID_PARAM;
    }
    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
ctc_asw_vlan_set_tagged_ports(uint8 lchip, uint16 vlan_id, ctc_port_bitmap_t port_bitmap)
{
    int32  ret = 0;
    uint32 cmd = 0;
    EvtTable_m evt;

    CTC_API_LOCK(lchip);
    cmd = DRV_IOR(EvtTable_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, vlan_id, cmd, &evt);
    if (!GetEvtTable(V, valid_f, &evt))
    {
        ret = ret ? ret : CTC_E_NOT_EXIST;
    }
    SetEvtTable(V, vlanUntagMap_f, &evt, ~(port_bitmap[0]));
    cmd = DRV_IOW(EvtTable_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : (DRV_IOCTL(lchip, vlan_id, cmd, &evt));
    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
ctc_asw_vlan_get_tagged_ports(uint8 lchip, uint16 vlan_id, uint8 gchip, ctc_port_bitmap_t port_bitmap)
{
    int32  ret = 0;
    uint32 cmd = 0;
    EvtTable_m evt;

    CTC_API_LOCK(lchip);
    cmd = DRV_IOR(EvtTable_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, vlan_id, cmd, &evt);
    if (GetEvtTable(V, valid_f, &evt))
    {
        port_bitmap[0] = GetEvtTable(V, vlanUntagMap_f, &evt);
        port_bitmap[0] = ~(port_bitmap[0]);
    }
    else
    {
        ret = ret ? ret : CTC_E_NOT_EXIST;
    }
    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
_ctc_asw_vlan_set_internal_property(uint8 lchip, uint16 vlan_id, ctc_asw_vlan_property_t vlan_prop, uint32 value)
{
    int32  ret = 0;
    uint32 cmd = 0;
    uint32 vlan_pro_index = 0;
    IvtTable_m ivt_table;
    IvtProfile_m ivt_profile;

    CTC_VLAN_RANGE_CHECK(vlan_id);

    sal_memset(&ivt_profile, 0, sizeof(ivt_profile));

    cmd = DRV_IOR(IvtTable_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, vlan_id, cmd, &ivt_table);
    vlan_pro_index  = GetIvtTable(V, vlanProfileIndex_f, &ivt_table);
    cmd = DRV_IOR(IvtProfile_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : (DRV_IOCTL(lchip, vlan_pro_index, cmd, &ivt_profile));
    switch (vlan_prop)
    {
        case CTC_VLAN_INT_PROP_TPID_INDEX:
            SetIvtProfile(V, stpidIndex_f, &ivt_profile, value);
            break;
        case CTC_VLAN_INT_PROP_VLAN_STORM_CTL_EN:
            SetIvtProfile(V, stcEn_f, &ivt_profile, value);
            break;
        case CTC_VLAN_INT_PROP_VLAN_STORM_CTL_PTR:
            SetIvtProfile(V, stcBaseIndex_f, &ivt_profile, value);
            break;
        default:
            return CTC_E_INVALID_PARAM;
    }
    cmd = DRV_IOW(IvtProfile_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : (DRV_IOCTL(lchip, vlan_pro_index, cmd, &ivt_profile));

    return ret;
}
/**
@brief    Get Vlan  properties
*/
int32
_ctc_asw_vlan_get_internal_property(uint8 lchip, uint16 vlan_id, ctc_asw_vlan_property_t vlan_prop, uint32* value)
{
    int32  ret = 0;
    uint32 cmd = 0;
    uint32 vlan_pro_index = 0;
    IvtTable_m ivt_table;
    IvtProfile_m ivt_profile;

    CTC_PTR_VALID_CHECK(value);
    CTC_VLAN_RANGE_CHECK(vlan_id);

    sal_memset(&ivt_profile, 0, sizeof(ivt_profile));

    cmd = DRV_IOR(IvtTable_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, vlan_id, cmd, &ivt_table);
    vlan_pro_index  = GetIvtTable(V, vlanProfileIndex_f, &ivt_table);
    cmd = DRV_IOR(IvtProfile_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : (DRV_IOCTL(lchip, vlan_pro_index, cmd, &ivt_profile));
    switch (vlan_prop)
    {
        case CTC_VLAN_INT_PROP_TPID_INDEX:
            *value = GetIvtProfile(V, stpidIndex_f, &ivt_profile);
            break;
        case CTC_VLAN_INT_PROP_VLAN_STORM_CTL_EN:
            *value  = GetIvtProfile(V, stcEn_f, &ivt_profile);
            break;
        case CTC_VLAN_INT_PROP_VLAN_STORM_CTL_PTR:
            *value  = GetIvtProfile(V, stcBaseIndex_f, &ivt_profile);
            break;
        default:
            return CTC_E_INVALID_PARAM;
    }

    return ret;
}

#define __VLAN_MAPPING_API__

/**
 @brief The function is to add one vlan mapping entry on the port in IPE
*/
int32
ctc_asw_vlan_add_vlan_mapping(uint8 lchip, uint32 gport, ctc_vlan_mapping_t* p_vlan_mapping)
{
    int32 ret = 0;
    uint8 index = 0;
    uint32 cmd = 0;
    uint16 ad_index = 0;
    ctc_vlan_hash_key_t hash_key;
    mask_tbl_entry_t cam_key;
    ds_t data;
    ds_t data_mask;
    mask_tbl_entry_t tmp_cam_key;
    IvmXReg_m ivm_x_reg_result;
    IvmXMaskReg_m ivm_x_mask_reg_result;

    cam_key.data_entry = (uint32 *)&data;
    cam_key.mask_entry = (uint32 *)&data_mask;
    tmp_cam_key.data_entry = (uint32 *)&ivm_x_reg_result;
    tmp_cam_key.mask_entry = (uint32 *)&ivm_x_mask_reg_result;

    CTC_PTR_VALID_CHECK(p_vlan_mapping);
    CTC_MAX_GPORT_CHECK(gport);

    CTC_API_LOCK(lchip);
    if (p_vlan_mapping->flag != CTC_VLAN_MAPPING_FLAG_USE_FLEX) /*hash key*/
    {
        sal_memset(&data, 0, sizeof(ds_t));
        sal_memset(&hash_key, 0, sizeof(ctc_vlan_hash_key_t));
        CTC_ERROR_RETURN_UNLOCK(_ctc_asw_vlan_mapping_get_key_type(lchip, gport, *p_vlan_mapping, &hash_key));
        if ( CTC_VLAN_HASH_KEY_TYPE_PORT == hash_key.key_type)
        {
            ad_index = gport + CTC_VLAN_PORT_AD_BASE;
        }
        else
        {
            CTC_ERROR_RETURN_UNLOCK(g_vlan_build_key_func_cb[hash_key.key_type](lchip, &hash_key, &data, 1));
            cmd = DRV_IOHA(g_vlan_hash_tbl[hash_key.key_type], DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN_UNLOCK(DRV_IOCTL(lchip, 0, cmd, &data));
            CTC_ERROR_RETURN_UNLOCK(_ctc_asw_vlan_get_ad_index(lchip, hash_key.key_type, &data, &ad_index));
        }
    }
    else  /*cam key*/
    {
        sal_memset(&data, 0, sizeof(IvmXReg_m));
        sal_memset(&data_mask, 0, sizeof(IvmXMaskReg_m));
        sal_memset(&ivm_x_reg_result, 0, sizeof(IvmXReg_m));
        sal_memset(&ivm_x_mask_reg_result, 0, sizeof(IvmXMaskReg_m));
        CTC_ERROR_RETURN_UNLOCK(_ctc_asw_vlan_mapping_build_cam_key(lchip, gport,  p_vlan_mapping, &data, &data_mask));
        for (index = 0; index < MAX_IVM_X_REG_NUM; index++)
        {
            if (CTC_IS_BIT_SET(g_ivm_x_bitmap[lchip], index))
            {
                cmd = DRV_IOR(IvmXReg_t, DRV_ENTRY_FLAG);
                ret = DRV_MASK_IOCTL(lchip, index, cmd, &tmp_cam_key);
                data_mask[1] |= 0xFFFFFFF8;
                if ((!sal_memcmp((char*)&data, (char*)&ivm_x_reg_result, sizeof(ivm_x_reg_result))) && (!sal_memcmp((char*)&data_mask, (char*)&ivm_x_mask_reg_result, sizeof(ivm_x_mask_reg_result))))
                {
                    CTC_API_UNLOCK(lchip);
                    return CTC_E_EXIST;
                }
            }
        }
    
        for (index = 0; index < MAX_IVM_X_REG_NUM; index++)
        {
            if (!CTC_IS_BIT_SET(g_ivm_x_bitmap[lchip], index))
            {
                cmd = DRV_IOW(IvmXReg_t, DRV_ENTRY_FLAG);
                ret = DRV_MASK_IOCTL(lchip, index, cmd, &cam_key);
                if (!ret)
                {
                    CTC_BIT_SET(g_ivm_x_bitmap[lchip], index);
                }
                ad_index = index + CTC_VLAN_TCAM_AD_BASE;
                break;
            }
            ret =  CTC_E_NO_RESOURCE;
        }
    }
    /* ad*/
    sal_memset(&data, 0, sizeof(IvmTable_m));
    ret = ret?ret:_ctc_asw_vlan_mapping_build_ad(lchip, p_vlan_mapping, &data);
    cmd = DRV_IOW(IvmTable_t, DRV_ENTRY_FLAG);
    ret = ret ? ret: DRV_IOCTL(lchip, ad_index, cmd, &data);
    CTC_API_UNLOCK(lchip);

    return ret;
}

/**
 @brief The function is to get one vlan mapping entry
*/
int32
ctc_asw_vlan_get_vlan_mapping(uint8 lchip, uint32 gport, ctc_vlan_mapping_t* p_vlan_mapping)
{
    int32 ret = 0;
    uint8 index = 0;
    uint32 cmd = 0;
    uint16 ad_index = 0;
    uint8 action_profile_index = 0;
    uint8 dt_action = 0;
    uint8 dt_stag_action = 0;
    uint8 dt_ctag_action = 0;
    uint8 sit_action = 0;
    uint8 sot_action = 0;
    /*ctc_vlan_tag_sl_t scos_action = 0;
    ctc_vlan_tag_sl_t ccos_action = 0;*/
    ctc_vlan_hash_key_t hash_key;
    mask_tbl_entry_t cam_key;
    ds_t data;
    ds_t data_mask;
    IvmXReg_m ivm_x_reg_result;
    IvmXMaskReg_m ivm_x_mask_reg_result;
    cam_key.data_entry = (uint32 *)&ivm_x_reg_result;
    cam_key.mask_entry = (uint32 *)&ivm_x_mask_reg_result;
    sal_memset(&data, 0, sizeof(ds_t));
    sal_memset(&data_mask, 0, sizeof(ds_t));

    CTC_PTR_VALID_CHECK(p_vlan_mapping);
    CTC_MAX_GPORT_CHECK(gport);

    CTC_API_LOCK(lchip);
    if (p_vlan_mapping->flag != CTC_VLAN_MAPPING_FLAG_USE_FLEX) /*hash key*/
    {
        sal_memset(&hash_key, 0, sizeof(ctc_vlan_hash_key_t));
        CTC_ERROR_RETURN_UNLOCK(_ctc_asw_vlan_mapping_get_key_type(lchip, gport, *p_vlan_mapping, &hash_key));
        if ( CTC_VLAN_HASH_KEY_TYPE_PORT == hash_key.key_type)
        {
            ad_index = gport + CTC_VLAN_PORT_AD_BASE;
        }
        else
        {
            CTC_ERROR_RETURN_UNLOCK(g_vlan_build_key_func_cb[hash_key.key_type](lchip, &hash_key, &data, 1));
            cmd = DRV_IOHL(g_vlan_hash_tbl[hash_key.key_type], DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN_UNLOCK(DRV_IOCTL(lchip, 0, cmd, &data));
            CTC_ERROR_RETURN_UNLOCK(_ctc_asw_vlan_get_ad_index(lchip, hash_key.key_type, &data, &ad_index));
        }
    }
    else  /*cam key*/
    {
        sal_memset(&ivm_x_reg_result, 0, sizeof(IvmXReg_m));
        sal_memset(&ivm_x_mask_reg_result, 0, sizeof(IvmXMaskReg_m));
        CTC_ERROR_RETURN_UNLOCK(_ctc_asw_vlan_mapping_build_cam_key(lchip, gport,  p_vlan_mapping, &data, &data_mask));
        for (index = 0; index < MAX_IVM_X_REG_NUM; index++)
        {
            if (CTC_IS_BIT_SET(g_ivm_x_bitmap[lchip], index))
            {
                cmd = DRV_IOR(IvmXReg_t, DRV_ENTRY_FLAG);
                ret = DRV_MASK_IOCTL(lchip, index, cmd, &cam_key);
                data_mask[1] |= 0xFFFFFFF8;
                if ((!sal_memcmp((char*)&data, (char*)&ivm_x_reg_result, sizeof(ivm_x_reg_result))) && (!sal_memcmp((char*)&data_mask, (char*)&ivm_x_mask_reg_result, sizeof(ivm_x_mask_reg_result))))
                {
                    ad_index = index + CTC_VLAN_TCAM_AD_BASE;
                    break;
                }
            }
            ret =  CTC_E_NOT_EXIST;
        }
    }
    /*decode ad*/
    cmd = DRV_IOR(IvmTable_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : DRV_IOCTL(lchip, ad_index, cmd, &data);
    if (GetIvmTable(V, policeMode_f, &data))
    {
        p_vlan_mapping->policer_id = GetIvmTable(V, policeIndex_f, &data);
    }
    if (GetIvmTable(V, counterEnable_f, &data))
    {
        CTC_SET_FLAG(p_vlan_mapping->action, CTC_VLAN_MAPPING_FLAG_STATS_EN);
        p_vlan_mapping->stats_id = GetIvmTable(V, counterIndex_f, &data);
    }
    p_vlan_mapping->new_svid = GetIvmTable(V, svid_f, &data);
    p_vlan_mapping->new_cvid = GetIvmTable(V, cvid_f, &data);

    p_vlan_mapping->new_scos = GetIvmTable(V, remarkScos_f, &data);
    p_vlan_mapping->new_scos = (p_vlan_mapping->new_scos >> 1);
    p_vlan_mapping->new_ccos = GetIvmTable(V, remarkCcos_f, &data);
    p_vlan_mapping->new_ccos = (p_vlan_mapping->new_ccos >> 1);
    /*scos_action = GetIvmTable(V, remarkScosMode_f, &data);
    ccos_action = GetIvmTable(V, remarkCcosMode_f, &data);*/

    action_profile_index = GetIvmTable(V, tagActionProfilePtr_f, &data);

    cmd = DRV_IOR(IvmActionProfile_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : DRV_IOCTL(lchip, action_profile_index, cmd, &data);
    dt_action = GetIvmActionProfile(V, dtTagAction_f, &data);
    dt_stag_action = dt_action & 0x3;
    dt_ctag_action = (dt_action >> 2) & 0x3;
    switch(dt_stag_action)
    {
    case 0 :
        p_vlan_mapping->stag_op = CTC_VLAN_TAG_OP_ADD;
        break;
    case 1:
        p_vlan_mapping->stag_op = CTC_VLAN_TAG_OP_DEL;
        break;
    case 2:
        sit_action = GetIvmActionProfile(V, sitTagAction_f, &data);
        p_vlan_mapping->stag_op = (sit_action&0x3) ? CTC_VLAN_TAG_OP_REP : CTC_VLAN_TAG_OP_REP_OR_ADD;
        break;
    case 3:
        p_vlan_mapping->stag_op = CTC_VLAN_TAG_OP_NONE;
        break;
    }

    switch(dt_ctag_action)
    {
    case 0 :
        p_vlan_mapping->ctag_op = CTC_VLAN_TAG_OP_ADD;
        break;
    case 1:
        p_vlan_mapping->ctag_op = CTC_VLAN_TAG_OP_DEL;
        break;
    case 2:
        sot_action = GetIvmActionProfile(V, sotTagAction_f, &data);
        p_vlan_mapping->ctag_op = (sot_action >> 2 & 0x3) ? CTC_VLAN_TAG_OP_REP : CTC_VLAN_TAG_OP_REP_OR_ADD;
        break;
    case 3:
        p_vlan_mapping->ctag_op = CTC_VLAN_TAG_OP_NONE;
        break;
    }
    CTC_API_UNLOCK(lchip);

    return ret;
}

/**
@brief The function is to update one vlan mapping entry on the port in IPE
*/
int32
ctc_asw_vlan_update_vlan_mapping(uint8 lchip, uint32 gport, ctc_vlan_mapping_t* p_vlan_mapping)
{
    int32 ret = 0;
    uint8 index = 0;
    uint32 cmd = 0;
    uint16 ad_index = 0;
    ctc_vlan_hash_key_t hash_key;
    IvmXReg_m ivm_x_reg_result;
    IvmXMaskReg_m ivm_x_mask_reg_result;
    mask_tbl_entry_t cam_key;
    ds_t data;
    ds_t data_mask;

    CTC_PTR_VALID_CHECK(p_vlan_mapping);
    CTC_MAX_GPORT_CHECK(gport);

    cam_key.data_entry = (uint32 *)&ivm_x_reg_result;
    cam_key.mask_entry = (uint32 *)&ivm_x_mask_reg_result;
    sal_memset(&data, 0, sizeof(ds_t));
    sal_memset(&data_mask, 0, sizeof(ds_t));
    sal_memset(&ivm_x_reg_result, 0, sizeof(IvmXReg_m));
    sal_memset(&ivm_x_mask_reg_result, 0, sizeof(IvmXMaskReg_m));

    CTC_API_LOCK(lchip);
    if (p_vlan_mapping->flag != CTC_VLAN_MAPPING_FLAG_USE_FLEX) /*hash key*/
    {
        sal_memset(&hash_key, 0, sizeof(ctc_vlan_hash_key_t));
        ret = _ctc_asw_vlan_mapping_get_key_type(lchip, gport, *p_vlan_mapping, &hash_key);
        if ( CTC_VLAN_HASH_KEY_TYPE_PORT == hash_key.key_type)
        {
            ad_index = gport + CTC_VLAN_PORT_AD_BASE;
        }
        else
        {
            ret = ret ? ret : g_vlan_build_key_func_cb[hash_key.key_type](lchip, &hash_key, &data, 1);
            cmd = DRV_IOHL(g_vlan_hash_tbl[hash_key.key_type], DRV_ENTRY_FLAG);
            ret = ret ? ret : DRV_IOCTL(lchip, 0, cmd, &data);
            ret = ret ? ret : _ctc_asw_vlan_get_ad_index(lchip, hash_key.key_type, &data, &ad_index);
        }
    }
    else  /*cam key*/
    {
        CTC_ERROR_RETURN_UNLOCK(_ctc_asw_vlan_mapping_build_cam_key(lchip, gport, p_vlan_mapping, &data, &data_mask));
        for (index = 0; index < MAX_IVM_X_REG_NUM; index++)
        {
            if (CTC_IS_BIT_SET(g_ivm_x_bitmap[lchip], index))
            {
                cmd = DRV_IOR(IvmXReg_t, DRV_ENTRY_FLAG);
                ret = DRV_MASK_IOCTL(lchip, index, cmd, &cam_key);
                if ((!sal_strcmp((char*)&data, (char*)&ivm_x_reg_result)) && (!sal_strcmp((char*)&data_mask, (char*)&ivm_x_mask_reg_result)))
                {
                    ad_index = index + CTC_VLAN_TCAM_AD_BASE;
                    break;
                }
            }
            ret =  CTC_E_NOT_EXIST;
        }
    }
    /*build ad*/
    sal_memset(&data, 0, sizeof(IvmTable_m));
    ret = ret ? ret : _ctc_asw_vlan_mapping_build_ad(lchip, p_vlan_mapping, &data);
    cmd = DRV_IOW(IvmTable_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : DRV_IOCTL(lchip, ad_index, cmd, &data);
    CTC_API_UNLOCK(lchip);

    return ret;
}

/**
 @brief The function is to remove one vlan mapping entry on the port in IPE
*/
int32
ctc_asw_vlan_remove_vlan_mapping(uint8 lchip, uint32 gport, ctc_vlan_mapping_t* p_vlan_mapping)
{
    int32 ret = 0;
    uint16 index = 0;
    uint32 cmd = 0;
    ctc_vlan_hash_key_t hash_key;
    IvmXReg_m ivm_x_reg_result;
    IvmXMaskReg_m ivm_x_mask_reg_result;
    mask_tbl_entry_t cam_key;
    ds_t data;
    ds_t data_mask;

    CTC_PTR_VALID_CHECK(p_vlan_mapping);
    CTC_MAX_GPORT_CHECK(gport);

    cam_key.data_entry = (uint32 *)&ivm_x_reg_result;
    cam_key.mask_entry = (uint32 *)&ivm_x_mask_reg_result;
    sal_memset(&data, 0, sizeof(ds_t));
    sal_memset(&data_mask, 0, sizeof(ds_t));
    sal_memset(&ivm_x_reg_result, 0, sizeof(IvmXReg_m));
    sal_memset(&ivm_x_mask_reg_result, 0, sizeof(IvmXMaskReg_m));

    CTC_API_LOCK(lchip);
    if (p_vlan_mapping->flag != CTC_VLAN_MAPPING_FLAG_USE_FLEX) /*hash*/
    {
        sal_memset(&hash_key, 0, sizeof(ctc_vlan_hash_key_t));
        ret =  _ctc_asw_vlan_mapping_get_key_type(lchip, gport, *p_vlan_mapping, &hash_key);
        if (CTC_VLAN_HASH_KEY_TYPE_PORT == hash_key.key_type)
        {
            index = gport + CTC_VLAN_PORT_AD_BASE;
            SetIvmTable(V, valid_f, &data, 1);
            SetIvmTable(V, svid_f, &data, 1);
            cmd = DRV_IOW(IvmTable_t, DRV_ENTRY_FLAG);
            ret = ret ? ret : DRV_IOCTL(lchip, index , cmd, &data);
        }
        else
        {
            ret = ret ? ret : g_vlan_build_key_func_cb[hash_key.key_type](lchip, &hash_key, &data, 0);
            cmd = DRV_IOHR(g_vlan_hash_tbl[hash_key.key_type], DRV_ENTRY_FLAG);
            ret = ret ? ret : DRV_IOCTL(lchip, 0, cmd, &data);
        }
    }
    else  /*cam*/
    {
        CTC_ERROR_RETURN_UNLOCK(_ctc_asw_vlan_mapping_build_cam_key(lchip, gport, p_vlan_mapping, &data, &data_mask));
        for (index = 0; index < MAX_IVM_X_REG_NUM; index++)
        {
            if (CTC_IS_BIT_SET(g_ivm_x_bitmap[lchip], index))
            {
                cmd = DRV_IOR(IvmXReg_t, DRV_ENTRY_FLAG);
                ret = DRV_MASK_IOCTL(lchip, index, cmd, &cam_key);
                data_mask[1] |= 0xFFFFFFF8;
                if ((!sal_memcmp((char*)&data, (char*)&ivm_x_reg_result, sizeof(ivm_x_reg_result))) && (!sal_memcmp((char*)&data_mask, (char*)&ivm_x_mask_reg_result, sizeof(ivm_x_mask_reg_result))))
                {
                    cmd = DRV_IOD(IvmXReg_t, DRV_ENTRY_FLAG);
                    ret = DRV_MASK_IOCTL(lchip, index, cmd, &cam_key);
                    if (!ret)
                    {
                        CTC_BIT_UNSET(g_ivm_x_bitmap[lchip], index);
                    }
                    break;
                }
            }
            ret =  CTC_E_NOT_EXIST;
        }
    }
    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
ctc_asw_vlan_create_vlan_range_group(uint8 lchip, ctc_vlan_range_info_t* vrange_info, bool is_svlan)
{
    CTC_PTR_VALID_CHECK(vrange_info);
    CTC_MAX_VALUE_CHECK(vrange_info->vrange_grpid, VLAN_RANGE_ENTRY_NUM - 1);
    if (CTC_IS_BIT_SET(g_vlan_range_bitmap[lchip], vrange_info->vrange_grpid))
    {
        return CTC_E_EXIST;
    }

    CTC_API_LOCK(lchip);
    CTC_BIT_SET(g_vlan_range_bitmap[lchip], vrange_info->vrange_grpid);
    if (is_svlan)
    {
        CTC_BIT_SET(g_vlan_range_bitmap[lchip], (vrange_info->vrange_grpid + VLAN_RANGE_ENTRY_NUM));
    }
    CTC_API_UNLOCK(lchip);

    return CTC_E_NONE;
}

int32
ctc_asw_vlan_destroy_vlan_range_group(uint8 lchip, ctc_vlan_range_info_t* vrange_info)
{
    int32 ret = CTC_E_NONE;
    uint8 idx = 0;
    uint32 cmd = 0;
    VlanRange_m vlan_range_table;
    int32 step = VlanRange_vlan0Max_f - VlanRange_vlan1Max_f;

    CTC_PTR_VALID_CHECK(vrange_info);
    VLAN_RANGE_GOUP_ID_CHECK(vrange_info);

    sal_memset(&vlan_range_table, 0, sizeof(vlan_range_table));

    CTC_API_LOCK(lchip);
    if (!CTC_IS_BIT_SET(g_vlan_range_bitmap[lchip], vrange_info->vrange_grpid))
    {
        ret =  CTC_E_NOT_EXIST;
    }
    for (idx = 0; idx < 4; idx++)
    {
        ret = ret ? ret : SetVlanRange(V, vlan0Max_f - step*idx, &vlan_range_table, 0);
        ret = ret ? ret : SetVlanRange(V, vlan0Min_f - step*idx, &vlan_range_table, 0);
    }
    cmd = DRV_IOW(VlanRange_t, DRV_ENTRY_FLAG);
    ret = ret ? ret: DRV_IOCTL(lchip, vrange_info->vrange_grpid, cmd, &vlan_range_table);
    if (!ret)
    {
        CTC_BIT_UNSET(g_vlan_range_bitmap[lchip], vrange_info->vrange_grpid);
        CTC_BIT_UNSET(g_vlan_range_bitmap[lchip], (vrange_info->vrange_grpid + VLAN_RANGE_ENTRY_NUM));
    }
    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
ctc_asw_vlan_add_vlan_range(uint8 lchip, ctc_vlan_range_info_t* vrange_info, ctc_vlan_range_t* vlan_range)
{
    int32 ret = 0;
    VlanRange_m vlan_range_table;
    uint32 cmd = 0;
    uint16 max = 0;
    uint16 min = 0;
    uint8 idx = 0;
    uint8 useful_idx = 0xFF;
    int32 step = VlanRange_vlan0Max_f - VlanRange_vlan1Max_f;

    CTC_PTR_VALID_CHECK(vrange_info);
    CTC_PTR_VALID_CHECK(vlan_range);
    VLAN_RANGE_GOUP_ID_CHECK(vrange_info);

    CTC_API_LOCK(lchip);
    cmd = DRV_IOR(VlanRange_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, vrange_info->vrange_grpid, cmd, &vlan_range_table);
    for (idx = 0; idx < 4; idx++)
    {
        max = GetVlanRange(V, vlan0Max_f - step*idx, &vlan_range_table);
        min = GetVlanRange(V, vlan0Min_f - step*idx, &vlan_range_table);
        if (max == 0 )
        {
            useful_idx = idx;
        }
        else if (((min <= vlan_range->vlan_start) && (vlan_range->vlan_start <= max))
            || ((min <= vlan_range->vlan_end) && (vlan_range->vlan_end <= max)))
        {
            CTC_API_UNLOCK(lchip);
            return CTC_E_INVALID_CONFIG;
        }
    }
    ret = (useful_idx != 0xFF) ? ret : CTC_E_NO_RESOURCE;
    ret = ret ? ret : SetVlanRange(V, vlan0Max_f - step*useful_idx, &vlan_range_table, vlan_range->vlan_end);
    ret = ret ? ret : SetVlanRange(V, vlan0Min_f - step*useful_idx, &vlan_range_table, vlan_range->vlan_start);
    cmd = DRV_IOW(VlanRange_t, DRV_ENTRY_FLAG);
    ret = ret ? ret: DRV_IOCTL(lchip, vrange_info->vrange_grpid, cmd, &vlan_range_table);
    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
ctc_asw_vlan_remove_vlan_range(uint8 lchip, ctc_vlan_range_info_t* vrange_info, ctc_vlan_range_t* vlan_range)
{
    int32 ret = 0;
    VlanRange_m vlan_range_table;
    uint32 cmd = 0;
    uint16 max = 0;
    uint16 min = 0;
    uint8 idx = 0;
    uint8 match_idx = 0xFF;
    int32 step = VlanRange_vlan0Max_f - VlanRange_vlan1Max_f;

    CTC_PTR_VALID_CHECK(vrange_info);
    CTC_PTR_VALID_CHECK(vlan_range);
    VLAN_RANGE_GOUP_ID_CHECK(vrange_info);

    CTC_API_LOCK(lchip);
    cmd = DRV_IOR(VlanRange_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, vrange_info->vrange_grpid, cmd, &vlan_range_table);
    for (idx = 0; idx < 4; idx++)
    {
        max = GetVlanRange(V, vlan0Max_f - step*idx, &vlan_range_table);
        min = GetVlanRange(V, vlan0Min_f - step*idx, &vlan_range_table);
        if (max == vlan_range->vlan_end && min == vlan_range->vlan_start)
        {
            match_idx = idx;
            break;
        }
    }
    ret = (match_idx != 0xFF) ? ret : CTC_E_NOT_EXIST;

    ret = ret ? ret : SetVlanRange(V, vlan0Max_f - step*match_idx, &vlan_range_table, 0);
    ret = ret ? ret : SetVlanRange(V, vlan0Min_f - step*match_idx, &vlan_range_table, 0);
    cmd = DRV_IOW(VlanRange_t, DRV_ENTRY_FLAG);
    ret = ret ? ret: DRV_IOCTL(lchip, vrange_info->vrange_grpid, cmd, &vlan_range_table);
    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
ctc_asw_vlan_get_vlan_range(uint8 lchip, ctc_vlan_range_info_t* vrange_info, ctc_vlan_range_group_t* vrange_group, uint8* count)
{
    int32 ret = 0;
    VlanRange_m vlan_range_table;
    uint32 cmd = 0;
    uint16 max = 0;
    uint16 min = 0;
    uint8 idx = 0;
    uint8 entry_idx = 0;
    int32 step = VlanRange_vlan0Max_f - VlanRange_vlan1Max_f;

    CTC_PTR_VALID_CHECK(vrange_info);
    CTC_PTR_VALID_CHECK(vrange_group);
    CTC_PTR_VALID_CHECK(count);
    VLAN_RANGE_GOUP_ID_CHECK(vrange_info);

    CTC_API_LOCK(lchip);
    cmd = DRV_IOR(VlanRange_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, vrange_info->vrange_grpid, cmd, &vlan_range_table);
    for (idx = 0; idx < 4; idx++)
    {
        max = GetVlanRange(V, vlan0Max_f - step*idx, &vlan_range_table);
        min = GetVlanRange(V, vlan0Min_f - step*idx, &vlan_range_table);
        if (max != 0)
        {
            vrange_group->vlan_range[entry_idx].vlan_start = min;
            vrange_group->vlan_range[entry_idx].vlan_end = max;
            entry_idx ++ ;
        }
    }
    *count = entry_idx;
    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
ctc_asw_vlan_get_vlan_range_type(uint8 lchip, ctc_vlan_range_info_t* vrange_info, bool* is_svlan)
{
    int32 ret = 0;

    CTC_PTR_VALID_CHECK(vrange_info);
    CTC_PTR_VALID_CHECK(is_svlan);

    CTC_API_LOCK(lchip);
    ret = _ctc_asw_vlan_get_internal_range_type(lchip, vrange_info, is_svlan);
    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
_ctc_asw_vlan_get_internal_range_type(uint8 lchip, ctc_vlan_range_info_t* vrange_info, bool* is_svlan)
{
    CTC_PTR_VALID_CHECK(vrange_info);
    CTC_PTR_VALID_CHECK(is_svlan);

    if (!CTC_IS_BIT_SET(g_vlan_range_bitmap[lchip], vrange_info->vrange_grpid))
    {
        return CTC_E_NOT_EXIST;

    }

    *is_svlan = CTC_IS_BIT_SET(g_vlan_range_bitmap[lchip], (vrange_info->vrange_grpid + VLAN_RANGE_ENTRY_NUM));
    return CTC_E_NONE;
}

#define __VLAN_CLASS_API__

int32
ctc_asw_vlan_add_vlan_class(uint8 lchip, ctc_vlan_class_t* p_vlan_class)
{
    int32 ret = 0;
    uint8 index = 0;
    uint32 cmd = 0;
    uint16 ad_index = 0;
    ctc_vlan_hash_key_t hash_key;
    mask_tbl_entry_t cam_key;
    ds_t data;
    ds_t data_mask;
    cam_key.data_entry = (uint32*)&data;
    cam_key.mask_entry = (uint32*)&data_mask;
    sal_memset(&data, 0, sizeof(ds_t));
    sal_memset(&data_mask, 0, sizeof(ds_t));

    CTC_PTR_VALID_CHECK(p_vlan_class);
    CTC_MAX_VALUE_CHECK(p_vlan_class->cos, 7);
    CTC_MAX_VALUE_CHECK(p_vlan_class->vlan_id, CTC_MAX_VLAN_ID);

    CTC_API_LOCK(lchip);
    if (!(p_vlan_class->flag & CTC_VLAN_CLASS_FLAG_USE_FLEX)) /*hash key*/
    {
        sal_memset(&data, 0, sizeof(ds_t));
        switch (p_vlan_class->type)
        {
        case (CTC_VLAN_CLASS_MAC):
            hash_key.key_type = CTC_VLAN_HASH_KEY_TYPE_MAC_SA;
            sal_memcpy(&(hash_key.macsa), &(p_vlan_class->vlan_class.mac), sizeof(mac_addr_t));
            break;
        case (CTC_VLAN_CLASS_IPV4):
            hash_key.key_type = CTC_VLAN_HASH_KEY_TYPE_IPV4_SA;
            sal_memcpy(&(hash_key.ipv4_sa), &(p_vlan_class->vlan_class.ipv4_sa), sizeof(ip_addr_t));
            break;
        case (CTC_VLAN_CLASS_IPV6):
            hash_key.key_type = CTC_VLAN_HASH_KEY_TYPE_IPV6_SA;
            sal_memcpy(&(hash_key.ipv6_sa), &(p_vlan_class->vlan_class.ipv6_sa), sizeof(ipv6_addr_t));
            break;
        default :
            CTC_API_UNLOCK(lchip);
            return CTC_E_NOT_SUPPORT;
        }
        CTC_ERROR_RETURN_UNLOCK(g_vlan_build_key_func_cb[hash_key.key_type](lchip, &hash_key, &data, 1));
        cmd = DRV_IOHA(g_vlan_hash_tbl[hash_key.key_type], DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, 0, cmd, &data);
        ret = ret ? ret : _ctc_asw_vlan_get_ad_index(lchip, hash_key.key_type, &data, &ad_index);
    }
    else  /*cam key*/
    {
        CTC_ERROR_RETURN_UNLOCK(_ctc_asw_vlan_class_build_cam_key(lchip, p_vlan_class, &data, &data_mask));
        for (index = 0; index < MAX_IVM_X_REG_NUM; index++)
        {
            if (!CTC_IS_BIT_SET(g_ivm_x_bitmap[lchip], index))
            {
                cmd = DRV_IOW(IvmXReg_t, DRV_ENTRY_FLAG);
                ret = DRV_MASK_IOCTL(lchip, index, cmd, &cam_key);
                if (!ret)
                {
                    CTC_BIT_SET(g_ivm_x_bitmap[lchip], index);
                }
                ad_index = index + CTC_VLAN_TCAM_AD_BASE;
                break;
            }
            ret =  CTC_E_NO_RESOURCE;
        }
    }
    /* build ad */
    sal_memset(&data, 0, sizeof(IvmTable_m));
    if (p_vlan_class->flag & CTC_VLAN_CLASS_FLAG_OUTPUT_COS)
    {
        SetIvmTable(V, remarkScosMode_f, &data, 0x1);
        SetIvmTable(V, remarkScos_f, &data, (p_vlan_class->cos << 1));
    }

    SetIvmTable(V, svid_f, &data, p_vlan_class->vlan_id);
    SetIvmTable(V, valid_f, &data, 1);
    cmd = DRV_IOW(IvmTable_t, DRV_ENTRY_FLAG);
    ret = ret ? ret: DRV_IOCTL(lchip, ad_index, cmd, &data);
    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
ctc_asw_vlan_remove_vlan_class(uint8 lchip, ctc_vlan_class_t* p_vlan_class)
{
    int32 ret = 0;
    uint8 index = 0;
    uint32 cmd = 0;
    IvmXReg_m ivm_x_reg_result;
    IvmXMaskReg_m ivm_x_mask_reg_result;
    mask_tbl_entry_t cam_key;
    ctc_vlan_hash_key_t hash_key;
    ds_t data;
    ds_t data_mask;

    cam_key.data_entry = (uint32 *)&ivm_x_reg_result;
    cam_key.mask_entry = (uint32 *)&ivm_x_mask_reg_result;
    sal_memset(&data, 0, sizeof(ds_t));
    sal_memset(&data_mask, 0, sizeof(ds_t));

    CTC_PTR_VALID_CHECK(p_vlan_class);

    CTC_API_LOCK(lchip);
    if (p_vlan_class->flag != CTC_VLAN_CLASS_FLAG_USE_FLEX) /*hash key*/
    {
        sal_memset(&hash_key, 0, sizeof(ctc_vlan_hash_key_t));
        switch(p_vlan_class->type)
        {
        case (CTC_VLAN_CLASS_MAC):
            hash_key.key_type = CTC_VLAN_HASH_KEY_TYPE_MAC_SA;
            sal_memcpy(&(hash_key.macsa), &(p_vlan_class->vlan_class.mac), sizeof(mac_addr_t));
            break;
        case (CTC_VLAN_CLASS_IPV4):
            hash_key.key_type = CTC_VLAN_HASH_KEY_TYPE_IPV4_SA;
            sal_memcpy(&(hash_key.ipv4_sa), &(p_vlan_class->vlan_class.ipv4_sa), sizeof(ip_addr_t));
            break;
        case (CTC_VLAN_CLASS_IPV6):
            hash_key.key_type = CTC_VLAN_HASH_KEY_TYPE_IPV6_SA;
            sal_memcpy(&(hash_key.ipv6_sa), &(p_vlan_class->vlan_class.ipv6_sa), sizeof(ipv6_addr_t));
            break;
        default :
            CTC_API_UNLOCK(lchip);
            return CTC_E_NOT_SUPPORT;
        }
        ret =  g_vlan_build_key_func_cb[hash_key.key_type](lchip, &hash_key, &data, 0);
        cmd = DRV_IOHR(g_vlan_hash_tbl[hash_key.key_type], DRV_ENTRY_FLAG);
        ret = ret ? ret : DRV_IOCTL(lchip, 0, cmd, &data);
    }
    else  /*cam key*/
    {
        sal_memset(&ivm_x_reg_result, 0, sizeof(IvmXReg_m));
        sal_memset(&ivm_x_mask_reg_result, 0, sizeof(IvmXMaskReg_m));
        CTC_ERROR_RETURN_UNLOCK(_ctc_asw_vlan_class_build_cam_key(lchip, p_vlan_class, &data, &data_mask));
        for (index = 0; index < MAX_IVM_X_REG_NUM; index++)
        {
            if (CTC_IS_BIT_SET(g_ivm_x_bitmap[lchip], index))
            {
                cmd = DRV_IOR(IvmXReg_t, DRV_ENTRY_FLAG);
                ret = DRV_MASK_IOCTL(lchip, index, cmd, &cam_key);
                if ((!sal_strcmp((char*)&data, (char*)&ivm_x_reg_result)) && (!sal_strcmp((char*)&data_mask, (char*)&ivm_x_mask_reg_result)))
                {
                    cmd = DRV_IOD(IvmXReg_t, DRV_ENTRY_FLAG);
                    ret = DRV_MASK_IOCTL(lchip, index, cmd, &cam_key);
                    if (!ret)
                    {
                        CTC_BIT_UNSET(g_ivm_x_bitmap[lchip], index);
                    }
                    break;
                }
            }
            ret =  CTC_E_NOT_EXIST;
        }
    }
    CTC_API_UNLOCK(lchip);

    return ret;
}

/**
 @brief init the vlan module
*/
int32
ctc_asw_vlan_init(uint8 lchip, ctc_vlan_global_cfg_t* vlan_global_cfg)
{
    int32  ret = 0;
    uint32 cmd = 0;
    uint8 sop_index = 0;
    uint8 cop_index = 0;
    uint8 cam_index = 0;
    IvtTable_m ivt;
    IvmActionProfile_m ivm_action_profile;
    EvtTable_m evt;
    IvmXIndex_m ivm_x_index;
    uint8 ivm_dt_tag_action[CTC_VLAN_TAG_OP_MAX - 1][CTC_VLAN_TAG_OP_MAX - 1] =
    {
        {0xf,    0xb,   0x3,    0x7,    0xb   },       /*stag op_none, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
        {0xe,    0xa,   0x2,    0x6,    0xa   },       /*stag op_rep_or_add, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
        {0xc,    0x8,   0x0,    0x4,    0x8   },       /*stag op_add, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
        {0xd,    0x9,   0x1,    0x5,    0x9   },       /*stag op_del, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
        {0xe,    0xa,   0x2,    0x6,    0xa   } 	 /*stag op_rep, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
    };

    /*stag valid(not zero), ctag invalid */
    uint8 ivm_sot_tag_action[CTC_VLAN_TAG_OP_MAX - 1][CTC_VLAN_TAG_OP_MAX - 1] =
    {
        {0xf,    0x3,   0x3,    0x7,    0xb   },       /*stag op_none, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
        {0xe,    0x2,   0x2,    0x6,    0xa   },       /*stag op_rep_or_add, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
        {0xc,    0x0,   0x0,    0x4,    0x8   },       /*stag op_add, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
        {0xd,    0x1,   0x1,    0x5,    0x9   },       /*stag op_del, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
        {0xe,    0x2,   0x2,    0x6,    0xa   } 	 /*stag op_rep, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
    };

    /*stag valid(zero), ctag invalid */
    uint8 ivm_sop_tag_action[CTC_VLAN_TAG_OP_MAX - 1][CTC_VLAN_TAG_OP_MAX - 1] =
    {
        {0xf,    0x3,   0x3,    0x7,    0xb   },       /*stag op_none, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
        {0xe,    0x2,   0x2,    0x6,    0xa   },       /*stag op_rep_or_add, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
        {0xc,    0x0,   0x0,    0x4,    0x8   },       /*stag op_add, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
        {0xd,    0x1,   0x1,    0x5,    0x9   },       /*stag op_del, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
        {0xe,    0x2,   0x2,    0x6,    0xa   } 	   /*stag op_rep, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
    };

    /*stag invalid, ctag valid(not zero) */
    uint8 ivm_sit_tag_action[CTC_VLAN_TAG_OP_MAX - 1][CTC_VLAN_TAG_OP_MAX - 1] =
    {
        {0xc,    0x8,   0x0,    0x4,    0x8   },       /*stag op_none, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
        {0xc,    0x8,   0x0,    0x4,    0x8   },       /*stag op_rep_or_add, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
        {0xc,    0x8,   0x0,    0x4,    0x8   },       /*stag op_add, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
        {0xd,    0x9,   0x1,    0x5,    0x9   },       /*stag op_del, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
        {0xe,    0xa,   0x2,    0x6,    0xa   } 	   /*stag op_rep, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
    };

    /*stag invalid, ctag valid(zero) */
    uint8 ivm_sip_tag_action[CTC_VLAN_TAG_OP_MAX - 1][CTC_VLAN_TAG_OP_MAX - 1] =
    {
        {0xc,    0x8,   0x0,    0x4,    0x8   },       /*stag op_none, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
        {0xc,    0x8,   0x0,    0x4,    0x8   },       /*stag op_rep_or_add, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
        {0xc,    0x8,   0x0,    0x4,    0x8   },       /*stag op_add, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
        {0xd,    0x9,   0x1,    0x5,    0x9   },       /*stag op_del, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
        {0xe,    0xa,   0x2,    0x6,    0xa   } 	   /*stag op_rep, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
    };

    uint8 ivm_ut_tag_action[CTC_VLAN_TAG_OP_MAX - 1][CTC_VLAN_TAG_OP_MAX - 1] =
    {
        {0xc,    0x0,   0x0,    0x4,    0x8   },       /*stag op_none, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
        {0xc,    0x0,   0x0,    0x4,    0x8   },       /*stag op_rep_or_add, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
        {0xc,    0x0,   0x0,    0x4,    0x8   },       /*stag op_add, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
        {0xd,    0x1,   0x1,    0x5,    0x9   },       /*stag op_del, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
        {0xe,    0x2,   0x2,    0x6,    0xa   } 	   /*stag op_rep, ctag op_none/op_rep_or_add/op_add/op_del/op_rep*/
    };
    sal_memset(&ivt, 0, sizeof(IvtTable_m));
    sal_memset(&ivm_action_profile, 0, sizeof(IvmActionProfile_m));
    sal_memset(&evt, 0, sizeof(EvtTable_m));
    sal_memset(&ivm_x_index, 0, sizeof(IvmXIndex_m));
    ret = _ctc_asw_vlan_register_build_key_fn();
    SetIvtTable(V, valid_f, &ivt, 1);
    SetIvtTable(V, fid_f, &ivt, 1);
    SetIvtTable(V, vlanMember_f, &ivt, 0xFFFFFFF);
    SetIvtTable(V, vlanProfileIndex_f, &ivt, 1);
    cmd = DRV_IOW(IvtTable_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : (DRV_IOCTL(lchip, 1, cmd, &ivt));
    SetEvtTable(V, valid_f, &evt, 1);
    SetEvtTable(V, vlanMember_f, &evt, 0xFFFFFFF);
    SetEvtTable(V, vlanUntagMap_f, &evt, 0xFFFFFFF);
    cmd = DRV_IOW(EvtTable_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : (DRV_IOCTL(lchip, 1, cmd, &evt));

/*init ivm action profile temple for vlan edit*/
    for (sop_index = CTC_VLAN_TAG_OP_NONE; sop_index < (CTC_VLAN_TAG_OP_MAX - 1); sop_index++)
    {
        for (cop_index = CTC_VLAN_TAG_OP_NONE; cop_index < (CTC_VLAN_TAG_OP_MAX - 1); cop_index++)
        {
            SetIvmActionProfile(V, dtTagAction_f, &ivm_action_profile, ivm_dt_tag_action[sop_index][cop_index] );
            SetIvmActionProfile(V, sotTagAction_f, &ivm_action_profile, ivm_sot_tag_action[sop_index][cop_index] );
            SetIvmActionProfile(V, sitTagAction_f, &ivm_action_profile, ivm_sit_tag_action[sop_index][cop_index] );
            SetIvmActionProfile(V, utTagAction_f, &ivm_action_profile, ivm_ut_tag_action[sop_index][cop_index] );
            SetIvmActionProfile(V, dtOpStagAction_f, &ivm_action_profile, ivm_dt_tag_action[sop_index][cop_index]);
            SetIvmActionProfile(V, dtIpCtagAction_f, &ivm_action_profile, ivm_dt_tag_action[sop_index][cop_index]);
            SetIvmActionProfile(V, sopTagAction_f, &ivm_action_profile, ivm_sop_tag_action[sop_index][cop_index]);
            SetIvmActionProfile(V, sipTagAction_f, &ivm_action_profile, ivm_sip_tag_action[sop_index][cop_index]);
            cmd = DRV_IOW(IvmActionProfile_t, DRV_ENTRY_FLAG);
            ret = ret ? ret : (DRV_IOCTL(lchip, g_ivm_action_profile_idx[sop_index][cop_index], cmd, &ivm_action_profile));
        }
    }

    /*init default ivm action profile*/
    SetIvmActionProfile(V, dtTagAction_f, &ivm_action_profile, 0xf);
    SetIvmActionProfile(V, dtOpStagAction_f, &ivm_action_profile, 0x0);
    SetIvmActionProfile(V, dtIpCtagAction_f, &ivm_action_profile, 0x3);
    SetIvmActionProfile(V, sotTagAction_f, &ivm_action_profile, 0xf);
    SetIvmActionProfile(V, sopTagAction_f, &ivm_action_profile, 0x4);
    SetIvmActionProfile(V, sitTagAction_f, &ivm_action_profile, 0xc);
    SetIvmActionProfile(V, sipTagAction_f, &ivm_action_profile, 0xc);
    SetIvmActionProfile(V, utTagAction_f, &ivm_action_profile, 0xc);
    cmd = DRV_IOW(IvmActionProfile_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : (DRV_IOCTL(lchip, 0, cmd, &ivm_action_profile));

    SetIvmActionProfile(V, dtTagAction_f, &ivm_action_profile, 0xf);
    SetIvmActionProfile(V, dtOpStagAction_f, &ivm_action_profile, 0x3);
    SetIvmActionProfile(V, dtIpCtagAction_f, &ivm_action_profile, 0x3);
    SetIvmActionProfile(V, sotTagAction_f, &ivm_action_profile, 0xf);
    SetIvmActionProfile(V, sopTagAction_f, &ivm_action_profile, 0xf);
    SetIvmActionProfile(V, sitTagAction_f, &ivm_action_profile, 0xf);
    SetIvmActionProfile(V, sipTagAction_f, &ivm_action_profile, 0xf);
    SetIvmActionProfile(V, utTagAction_f, &ivm_action_profile, 0xf);
    cmd = DRV_IOW(IvmActionProfile_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : (DRV_IOCTL(lchip, 1, cmd, &ivm_action_profile));

    for (cam_index = 0; cam_index < MAX_IVM_X_REG_NUM; cam_index++)
    {
        SetIvmXIndex(V, ivmIndex_f, &ivm_x_index, (cam_index + CTC_VLAN_TCAM_AD_BASE));
        cmd = DRV_IOW(IvmXIndex_t, DRV_ENTRY_FLAG);
        ret = ret ? ret : (DRV_IOCTL(lchip, cam_index, cmd, &ivm_x_index));
    }
    return ret;
}

int32
ctc_asw_vlan_deinit(uint8 lchip)
{
    return CTC_E_NONE;
}
